import type { FC } from 'react';
import { useMemo } from 'react';
import { useMemoizedFn, useSafeState } from 'ahooks';
import { LinearGradient } from 'expo-linear-gradient';

import {
  Text,
  ViewStyle,
  TextStyle,
  StyleSheet,
  TouchableOpacity,
  ActivityIndicator
} from 'react-native';

import Space from '../Space';

import {
  whiteColor,
  primaryColor
} from '@/constants/Colors';

import {
  btnStyles,
  textStyles,
  textSizes,
  btnSizes,
  loadingSizes,
  linearColors
} from './styles';

import type { ButtonProps } from './types';

const Button: FC<ButtonProps> = (props) => {
  const {
    loadingSize,
    size = 'middle',
    type = 'default',
    disabled = false,
    round = false,
    ghost = false,
    loading = false
  } = props;

  const [focus, setFocus] = useSafeState(false);

  const onPressIn = useMemoizedFn(() => {
    setFocus(true);
    props.onPress?.();
  });

  const onPressOut = useMemoizedFn(() => {
    setFocus(false);
  });

  const btnSize = useMemo(() => {
    return typeof size === 'string' ?
      btnSizes[size] : size;
  }, [size]);

  const colors = useMemo(() => {
    let colorType = type as string;

    if (disabled) {
      return linearColors.disabled;
    }

    if (type === 'primary' && ghost) {
      colorType = 'ghost';
    }

    if (focus) {
      colorType += '_focus';
    };
    return linearColors[colorType as never];
  }, [focus, type, disabled, ghost]);

  const wrapperStyles = useMemo(() => {
    let borderRadius = 6;
    let _styles: ViewStyle = btnStyles[type];

    if (round) {
      borderRadius = btnSize / 2;
    }

    if (type === 'primary' && ghost) {
      _styles = btnStyles.ghost;
    }

    if (disabled) {
      _styles = btnStyles.disabled;
    }

    return StyleSheet.flatten([
      btnStyles.btn,
      {
        height: btnSize,
        borderRadius
      },
      _styles
    ]);
  }, [btnSize, type, disabled, round, ghost]);

  const btnTextStyles = useMemo(() => {
    let _styles: TextStyle = textStyles[type];

    const _sizeStyles: TextStyle = {
      fontSize: textSizes[size]
    };

    if (type === 'primary' && ghost) {
      _styles = textStyles.ghost;
    }

    if (disabled) {
      _styles = textStyles.disabled;
    }

    return StyleSheet.flatten([
      textStyles.btn_text,
      _sizeStyles,
      _styles,
    ]);

  }, [type, disabled, size, ghost]);

  const renderPrefix = () => {
    if (!loading) {
      return props.icon;
    }
    const color = (() => {
      if (type !== 'primary') {
        return primaryColor;
      }
      return ghost ?
        primaryColor :
        whiteColor;
    })();

    return (
      <ActivityIndicator
        color={color}
        size={loadingSize ?? loadingSizes[size]}
      />
    );
  }

  return (
    <TouchableOpacity
      activeOpacity={.8}
      onPressIn={onPressIn}
      onPressOut={onPressOut}
      disabled={disabled || loading}
      style={[wrapperStyles, props.style]}
    >
      <LinearGradient
        end={{ x: 1, y: 1 }}
        start={{ x: 0, y: 0 }}
        colors={colors as [string, string]}
        style={[btnStyles.btn_in, props.innerStyle]}
      >
        <Space style={btnStyles.center} size={6}>
          {renderPrefix()}
          <Text style={[btnTextStyles, props.textStyle]}>
            {props.title}
          </Text>
          {props.suffix}
        </Space>
      </LinearGradient>
    </TouchableOpacity>
  );
}

export default Button;